home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Frameworks / Hsoi's App Shell 1.0a4 / Hsoi's App Shell Source / HASDialogs.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-28  |  56.3 KB  |  1,850 lines  |  [TEXT/CWIE]

  1. /*
  2.     HASDialogs.c from Hsoi's App Shell. © 1995-1997 John C. Daub.  All rights reserved.
  3.  
  4.     This file contains the "big" functions for dealing with most every dialog box in
  5.     the shell:  modal, modeless, movable modal, about, splash, registration, etc.
  6.     (the help dialog box, cool about box (the funky animated scrolling credits thing),
  7.     preferences, etc. are covered in their own files).
  8.     
  9.     Utility functions for dialogs (pretty much code that's more easily reusable than
  10.     these functions) can be foundin HASUtilDialogs.c
  11.     
  12.     Lots of the stuff in here are derrived, gleaned from, adapted from, based upon,
  13.     (whatever) stuff from books (like Scott Knaser's "Macintosh Programming Secrets"
  14.     2nd ed.) and stuff off the net and from Apple DTS code snippets (like the Modal
  15.     dialog)
  16. */
  17.  
  18. #pragma mark ••• #includes •••
  19.  
  20. #ifndef _WASTE_
  21. #include "WASTE.h"
  22. #endif
  23. #include "HASGlobals.h"
  24. #ifndef __HSOIS_APP_SHELL__
  25. #include "HASMain.h"
  26. #endif
  27. #include "HASMovableModal.h"
  28. #include "HASDialogs.h"
  29. #include "HASMenus.h"
  30. #include "HASUtilDialogs.h"
  31. #include "HASWindows.h"
  32. #include "HASUtilities.h"
  33. #include "HASUtilPStrings.h"
  34. #include "HASUtilCursors.h"
  35.  
  36. #include "WASTE_Objects.h"
  37.  
  38. #ifndef __DIALOGS__
  39. #include <Dialogs.h>
  40. #endif
  41. #ifndef __ICONS__
  42. #include <Icons.h>
  43. #endif
  44. #ifndef __SOUND__
  45. #include <Sound.h>
  46. #endif
  47. #ifndef __SPEECH__
  48. #include <Speech.h>
  49. #endif
  50.  
  51. #pragma mark -
  52. #pragma mark ••• Globals and constants •••
  53.  
  54. //    The following globals are for the movable modal dialog/progress bar stuff
  55.  
  56. GrafPtr        pProgressPort;
  57. Rect        pRect;
  58. long        pMax;
  59. long        pCurrent;
  60. long        pLastCurrent;
  61. short        pLastBorder;
  62.  
  63. static    const RGBColor    kMMBlack        = {0x0000, 0x0000, 0x0000};
  64. static    const RGBColor    kMMWhite        = {0xFFFF, 0xFFFF, 0xFFFF};
  65. static    const RGBColor    kMMDarkGrey        = {0x4444, 0x4444, 0x4444};
  66. static    const RGBColor    kMMSteelBlue    = {0xCCCC, 0xCCCC, 0xFFFF};
  67.  
  68. #pragma mark -
  69. #pragma mark ••• Misc Dialog Boxes •••
  70.  
  71.  
  72. /*
  73.  *    let's do the regular old about box
  74.  */
  75.  
  76.  
  77. void    HsoiDoAboutBox( void )
  78. {
  79.     short                itemHit;
  80.     unsigned short        randNum;
  81.     long                range;
  82.     short                resID;
  83.     SndListHandle        sndHandle;
  84.     VersRecHndl            version;
  85.     StringHandle        appName;
  86.     DialogRef            aboutBox;
  87.     Handle                iHandle;
  88.     GrafPtr                oldPort;
  89.     ModalFilterUPP        aboutBoxFilter = nil;
  90.     Size                handleSize;
  91.     
  92.     // if we have a sound playing, stop it before we proceed
  93.     
  94.     if ( SoundIsPlaying() )
  95.         StopCurrentSound();
  96.     
  97.     // we have a bunch of information to get from the application to put
  98.     // into the about box...so, let's get it all!
  99.     
  100.     // first, the app name.
  101.     
  102. //    appName = (StringHandle)GetResource( 'STR ', strAppNameString );
  103. //    DetachResource( (Handle)appName );
  104. //    HLock( (Handle)appName );
  105.  
  106.     // get the app name from a 'STR ' resource
  107.     
  108.     appName = GetString( strAppNameString );
  109.     
  110.     // since we will be manipulating the data as a Pascal string, we ought to
  111.     // make sure we expand the storage potential to it's maximum size (this is
  112.     // something I gleaned from THINK Reference since the size of the storage
  113.     // for the returned handled is based on the actual size of the string,
  114.     // as indicated by its length byte).
  115.     
  116.     // also, according to IM:Memory, SetHandleSize might need to move the handle
  117.     // around in memory in order to resize it.  so, we need to make sure the
  118.     // handle is unlocked before we call.
  119.     
  120.     HUnlock( (Handle)appName );
  121.     
  122.     handleSize = sizeof( Str255 );
  123.     SetHandleSize( (Handle)appName, handleSize );
  124.     
  125.     // detach the resource (turn a resource handle into a regular handle)
  126.     
  127.     DetachResource( (Handle)appName );
  128.     
  129.     // and lock it down
  130.     
  131.     HLock( (Handle)appName );
  132.     
  133.     // now get the version number
  134.     
  135.     version = (VersRecHndl)GetResource( 'vers', 1 );
  136.     DetachResource( (Handle)version );
  137.     HLock( (Handle)version );
  138.     
  139.     // since we have to combine the app name and the version string, let's do so.
  140.     
  141.     HsoiConcatString( *appName, "\p " );    // need to stick a space in there so the
  142.                                             // words don't run together
  143.     HsoiConcatString( *appName, (*version)->shortVersion );
  144.     
  145.     // and the copyright info will just be from a macro
  146.     // and the user name and organization we just get from the prefs
  147.  
  148.     // now, let's get the dialog
  149.     
  150.     aboutBox = GetNewDialog( rAboutBoxDLOG, nil, MOVE_TO_FRONT );
  151.     
  152.     // if we didn't get it, just beep and return
  153.     
  154.     if ( aboutBox == nil )
  155.     {
  156.         SysBeep(5);
  157.         goto exit;
  158.     }
  159.     
  160.     // set the port
  161.     
  162.     GetPort( &oldPort );
  163.     SetGrafPortOfDialog( aboutBox );
  164.     
  165.     // now, set the static text items to what they should be
  166.     
  167.     iHandle = HsoiGetDialogItemHandle( aboutBox, iAboutBoxAppName );
  168.     SetDialogItemText( iHandle, *appName );
  169.     
  170.     // fyi:  there is a Str255 in the 'vers' record that you COULD use for this
  171.     // (in the VersRec in UnivHeaders 2.1f, the struct member name is "reserved")
  172.     // but since it's reserved and some packed info, best not to for now.
  173.     
  174.     iHandle = HsoiGetDialogItemHandle( aboutBox, iAboutBoxCopyright );
  175.     SetDialogItemText( iHandle, APP_COPYRIGHT );
  176.     
  177.     iHandle = HsoiGetDialogItemHandle( aboutBox, iAboutBoxUser );
  178.     SetDialogItemText( iHandle, gMyPrefs.userName );
  179.     
  180.     iHandle = HsoiGetDialogItemHandle( aboutBox, iAboutBoxOrg );
  181.     SetDialogItemText( iHandle, gMyPrefs.userOrg );
  182.     
  183.     // since we're going to use the standard dialog filter, we usually don't
  184.     // need to call such things as SetDialogCancelItem(). however, since
  185.     // item #2 in this dialog is NOT a button, we'll call it ourselves to
  186.     // allow the ok button to also double as the cancel button (this way, you
  187.     // could press return and/or esc to dismiss the dialog)
  188.     
  189.     SetDialogCancelItem( aboutBox, ok );
  190.     
  191.     
  192.     // now, initialize the random number generator
  193.     
  194.     GetDateTime( (unsigned long *)&qd.randSeed );
  195.  
  196.     // get the valid range of numbers.  we have 4 "valid" sounds in the resource file
  197.     // (5000 - 5003), so that's the range ( 5003 - 5000 + 1 = 4 )
  198.  
  199.     range = kAboutSoundMax - kAboutSoundMin + 1;
  200.     
  201.     // get a random number
  202.     // the do-while loop really isn't necessary, but just to guard against some strange
  203.     // case, this'll happen at least once, but go again if the resID happens to be out
  204.     // of range.
  205.     
  206.     do
  207.     {
  208.         randNum = Random();
  209.  
  210.     
  211.         // and now to find the valid 'snd ' resource ID number
  212.         // this'll give a number between 0 and 3 inclusive
  213.     
  214.         resID = ( randNum * range ) / 65536;
  215.     } while( (resID < 0) || (resID > range) );
  216.     
  217.     resID += 5000;  // add 5000 to it to get the res id number
  218.     
  219.     // get that sound's handle
  220.     
  221.     sndHandle = (SndListHandle)GetResource( TYPE_SOUND, resID );
  222.     
  223.     // make sure we got it.  if so, play it, then axe it
  224.     
  225.     if ( sndHandle != nil )
  226.     {
  227.         HLock( (Handle)sndHandle );
  228.         SndPlay( nil, sndHandle, true );
  229.         HUnlock( (Handle)sndHandle );
  230.         HsoiForgetResource( (Handle *)&sndHandle );
  231.     }
  232.     
  233.     // display the about box
  234.     
  235.     
  236.     ShowWindow( GetDialogWindow( aboutBox ) );
  237.     
  238.     // make a happy cursor
  239.     
  240.     InitCursor();
  241.     
  242.     // kick into ModalDialog until they leave
  243.     
  244.     aboutBoxFilter = HsoiGetMyStandardDialogFilter();
  245.     
  246.     do {
  247.         ModalDialog( aboutBoxFilter, &itemHit );
  248.         
  249.         // this is just to be a smart-ass ;)
  250.         
  251.         if ( (itemHit == iAboutBoxIcon) && gHasSpeechManager )
  252.         {
  253.             SpeakString( "\pWhat, did you think clicking on the icon would do something special?" );
  254.             while ( SpeechBusy() != nil )
  255.                 ;
  256.         }                
  257.             
  258.     } while ( (itemHit != ok) && (itemHit != cancel) );
  259.     
  260.     
  261. exit:
  262.  
  263.     if ( aboutBoxFilter != nil )
  264.         DisposeRoutineDescriptor( aboutBoxFilter );
  265.     
  266.     if ( appName != nil )
  267.     {
  268.         HUnlock( (Handle)appName );
  269. //        HsoiForgetResource( (Handle *)&appName );
  270.         HsoiForgetHandle( (Handle *)&appName );
  271.     }
  272.     
  273.     if ( version != nil )
  274.     {
  275.         HUnlock( (Handle)version );
  276. //        HsoiForgetResource( (Handle *)&version );
  277.         HsoiForgetHandle( (Handle *)&version );
  278.     }
  279.  
  280.     if ( aboutBox != nil )
  281.         DisposeDialog( aboutBox );
  282.         
  283.     SetPort( oldPort );
  284.     
  285.     // and that's all she wrote....boring?  i know...
  286.     
  287.     return;
  288. }
  289.  
  290.  
  291. /*
  292.  *    this does our splash screen.
  293.  */
  294.  
  295. // normally, you don't want strings to be hard coded like this (for localization).  but in
  296. // this one case, we're gonna make an exception.
  297.  
  298. Boolean    HsoiDoSplashScreen( void )
  299. {
  300.     GrafPtr            oldPort;
  301.     DialogRef        splashDialog;
  302.     RGBColor        oldForeColor;
  303.     Rect            logoRect;
  304.     short            dialogWidth,
  305.                     dialogCenter,
  306.                     strWidth,
  307.                     halfStrWidth,
  308.                     offset;
  309.     Point            currentPosition;
  310.     FontInfo        theFontInfo;
  311.     register short    lineHeight;
  312.     Str255            text;
  313.     PicHandle        logoPICT;
  314.     Boolean            weSpoke;
  315.     long            waitTicks;
  316.     EventRecord        event;
  317.     
  318.  
  319.     // get the dialog box
  320.     
  321.     splashDialog = GetNewDialog( rSplashScreen, nil, MOVE_TO_FRONT );
  322.     
  323.     // if we didn't get a dialog box, we'll just skip the whole splash screen affair
  324.     
  325.     if ( splashDialog == nil )
  326.         return false;
  327.     
  328.     // let's try to get the logo pict.  if we don't get it, skip it all.
  329.     
  330.     logoPICT = GetPicture( rLogoPICT );
  331.     if ( logoPICT == nil )
  332.     {
  333.         DisposeDialog( splashDialog );
  334.         return false;
  335.     }
  336.     
  337.     // ok, we got our stuff, let's set the current drawing/graphics port to the dialog.
  338.     
  339.     GetPort( &oldPort );
  340.     SetGrafPortOfDialog( splashDialog );
  341.     
  342.     // set the cursor to an arrow (cause who knows what it'll be otherwise)
  343.     
  344.     InitCursor();
  345.     
  346.     // reset the drawing pen
  347.     
  348.     PenNormal();
  349.     
  350.     // let's set the text style (boring style yes, but i can be 99.9% sure that just
  351.     // about any Mac (with a Roman script system) will have Geneva 12 since it's burned
  352.     // into the ROMs.  Again, this is bad for localization, but i don't intend on
  353.     // distribution (right now at least) to non-Roman systems (cause I have no way of
  354.     // programming nor testing on any other system than my computer at home and work)
  355.     
  356.     TextFont( geneva );
  357.     TextSize( 12 );
  358.     TextMode( srcOr );
  359.  
  360.     // let's set the fore color (the text will appear in this color) to white, but how
  361.     // we set it all depends on the quickdraw version available.  Since we're running
  362.     // system 7 at least, it's probably not necessary to check for this, but can't hurt.
  363.     
  364.     if ( gHasColorQD )
  365.     {
  366.         GetForeColor( &oldForeColor );
  367.         RGBForeColor( &kMMWhite );
  368.     }
  369.     else
  370.         PenPat(&qd.white);
  371.     
  372.     // get some measurements so we know where to draw strings..
  373.     
  374.     dialogWidth = GetWindowPort((WindowRef)splashDialog)->portRect.right - 
  375.                     GetWindowPort((WindowRef)splashDialog)->portRect.left;
  376.     dialogCenter = dialogWidth / 2;
  377.     
  378.     HsoiGetDialogItemRect( splashDialog, 1, &logoRect );
  379.     
  380.     // show the thing (yea, it's empty...we'll draw things as sthey happen so we don't
  381.     // have to worry about updating the thing (hopefuly))
  382.     
  383.     ShowWindow( GetDialogWindow(splashDialog) );
  384.     
  385.     // throw in the logo
  386.     
  387.     DrawPicture( logoPICT, &logoRect );
  388.     
  389.     // Draw all the strings.  All the funky calculations are to allow things to be
  390.     // centered horizontally and spaced nicely vertically.
  391.     
  392.     HsoipStringCopy( APP_COPYRIGHT, text );
  393.     strWidth = StringWidth( text );
  394.     halfStrWidth = strWidth / 2;
  395.     offset = dialogCenter - halfStrWidth;
  396.     MoveTo( offset, logoRect.bottom + 20 );
  397.     DrawString( text );
  398.     
  399.     GetPen( ¤tPosition );
  400.     GetFontInfo( &theFontInfo );
  401.     lineHeight = theFontInfo.ascent + theFontInfo.descent + theFontInfo.leading;
  402.     
  403.     HsoipStringCopy( "\pRegistered to:", text );
  404.     strWidth = StringWidth( text );
  405.     halfStrWidth = strWidth / 2;
  406.     offset = dialogCenter - halfStrWidth;
  407.     MoveTo( offset, currentPosition.v + lineHeight + lineHeight ); // move down 2 lines
  408.     DrawString( text );
  409.     
  410.     GetPen( ¤tPosition );
  411.     strWidth = StringWidth( gMyPrefs.userName );
  412.     halfStrWidth = strWidth / 2;
  413.     offset = dialogCenter - halfStrWidth;
  414.     MoveTo( offset, currentPosition.v + lineHeight + lineHeight );
  415.     DrawString( gMyPrefs.userName );
  416.     
  417.     GetPen( ¤tPosition );
  418.     strWidth = StringWidth( gMyPrefs.userOrg );
  419.     halfStrWidth = strWidth / 2;
  420.     offset = dialogCenter - halfStrWidth;
  421.     MoveTo( offset, currentPosition.v + lineHeight );
  422.     DrawString( gMyPrefs.userOrg );
  423.         
  424.     // all the strings are drawn...let's be cute and use the Speech Manager.
  425.     
  426.     if ( gHasSpeechManager && gMyPrefs.doStartupSpeech )
  427.     {
  428.         SpeakString( "\pWelcome to Hsoi's App Shell." );
  429.         while( SpeechBusy() != nil )
  430.             ; // do nothing, just wait until it's done speaking
  431.         weSpoke = true;
  432.     }
  433.     else
  434.         weSpoke = false;
  435.  
  436.     // get rid of any key and mouse events in the queue before we go..
  437.     
  438.     FlushEvents(mDownMask | mUpMask | keyDownMask | keyUpMask | autoKeyMask, 0);
  439.  
  440.     // now draw saying they can click the mouse to continue
  441.     
  442.     GetPen( ¤tPosition );
  443.     HsoipStringCopy( "\p(Click mouse button to continue)", text );
  444.     strWidth = StringWidth( text );
  445.     halfStrWidth = strWidth / 2;
  446.     offset = dialogCenter - halfStrWidth;
  447.     MoveTo( offset, currentPosition.v + lineHeight + lineHeight );
  448.     DrawString( text );
  449.     
  450.     // now just sit around waiting for them to click the mouse button, OR if the
  451.     // dialog's been up for 30 seconds, dump it anyways
  452.     
  453.     waitTicks = TickCount() + 1800; // 1800 ticks == 30 seconds
  454.     
  455.     // and it's nice to keep getting events here so that it doesn't seem like
  456.     // the computer is locked up (things in the background can continue to
  457.     // function, etc)
  458.     
  459.     do {
  460.     
  461.         // get the next event
  462.         
  463.         GetNextEvent( mDownMask, &event );
  464.         
  465.         // give a little time to the system
  466.         
  467.         SystemTask();
  468.         
  469.         // if 30 seconds hasn't yet elapsed, keep looping, or break out
  470.         
  471.         if ( TickCount() <= waitTicks )
  472.             continue;
  473.         else
  474.             break;
  475.     
  476.         // or if we got a mouseDown event, kick out
  477.         
  478.     } while ( event.what != mouseDown );
  479.  
  480.     // now, i probably could have done the above in a simpler manner...just forget all
  481.     // the GetNextEvent stuff and call Button() to see if the button got clicked.  but
  482.     // i like this way better cause it allows stuff in the background (especially
  483.     // a user's clock, like if there's one in the menubar) to get updated...and like
  484.     // with the clock thing, it could allow the user to know their computer didn't freeze.
  485.     // also, you could easily expand this to not only look for the mouse, but like if
  486.     // you wanted to allow the user to hit the mouse or hit any key (or even a specific
  487.     // key(s) like return and/or space bar) you could add that sort of filtering in here.
  488.     // so, tho this is a bit more of a consuming way to do things, it could be much more
  489.     // easily expanded and flexible, IMHO
  490.     
  491.     // and once again flush things so things don't click through
  492.     
  493.     FlushEvents(mDownMask | mUpMask | keyDownMask | keyUpMask | autoKeyMask, 0);
  494.     
  495.     // clean up
  496.     
  497.     DisposeDialog( splashDialog );
  498.     RGBForeColor( &oldForeColor );
  499.     SetPort( oldPort );
  500.  
  501.     return weSpoke;
  502. }
  503.  
  504.  
  505.  
  506. /*
  507.     This will allow the user to change the font size to just about any size they
  508.     feel like it.
  509.     
  510.     Marco Piovanelli notified me that Apple wants us to allow people to change to
  511.     font sizes up to 32,767 points.  Well, i tired that and that just gets plain
  512.     silly...you can't even see the thing (i couldn't see much after around 2000 points).
  513.     
  514.     So, to keep things a wee bit more practical, we'll just go up to 500 points (if
  515.     that's still practical).  But it is possible to go up to 32,767 points.  If you
  516.     want to support this much, just be sure to change the appropriate things not only
  517.     here, but also in the filter.
  518.  
  519.     Speaking of Marco, to handle this dialog, i used to use a modal dialog, tho that's
  520.     not really practical.  I then tried to use my HelpModalDialog from the help stuff.  That
  521.     worked ok.  But, just to show off another way to do a movable modal dialog, I'm using
  522.     the MovableModal Library 2.0 source from Marco Piovanelli.  Marco has some neat stuff
  523.     to really make it stand alone, however there is *1* problem:  i can't get the
  524.     menus to disable and reenable properly with Marco's code.  *shrug*  it's not something
  525.     I'll sweat for now (maybe you want to?).  So, you'll see commented out in the code
  526.     the places where the calls belong, but the only thing from this lib that I'm using
  527.     is the actualy MovableModalDialog() call.
  528. */
  529.  
  530. long    HsoiDoOtherFontSize( WindowRef theWindow )
  531. {
  532.     DialogRef            theDialog;
  533.     short                itemHit;
  534.     long                fontSize = 12;
  535.     Handle                itemHandle;
  536.     Str255                itemText;
  537.     short                mode = weDoAll;
  538.     TextStyle            ts;
  539.     Boolean                zeroFont = false;
  540.     ModalFilterUPP        fontSizeFilterProc = nil;
  541.     Handle                okButtonHandle;
  542.  
  543.     // if we have a sound playing, stop it before we proceed
  544.     
  545.     if ( SoundIsPlaying() )
  546.         StopCurrentSound();
  547.     
  548.     // let's get our dialog.  set the dialog to track the cursor movement.
  549.     // no need to SetDialogDefaultItem() or SetDialogCancelItem() cause 
  550.     // the dialog filter handles all that.
  551.     
  552.     theDialog = GetNewDialog( rOtherFontSizeDialog, nil, MOVE_TO_FRONT );
  553.     SetDialogTracksCursor( theDialog, true );
  554.     
  555.     // let's get our dialog filter
  556.     
  557.     fontSizeFilterProc = NewModalFilterProc( hsoiOtherFontSizeDialogFilter );    
  558.     
  559.     // grab a handle to the OK button for dimming (this is a cute technique)
  560.     
  561.     okButtonHandle = HsoiGetDialogItemHandle( theDialog, ok );
  562.         
  563.     // set the number in the dialog to be whatever the current font size is
  564.     
  565.     WEContinuousStyle( (unsigned short *)&mode, &ts, HsoiGetWindowWE(theWindow) );
  566.     if ((mode & weDoSize) != 0 )
  567.     {
  568.         NumToString( ts.tsSize, itemText );
  569.         itemHandle = HsoiGetDialogItemHandle( theDialog, iOtherSizeSizeEditText );
  570.         SetDialogItemText( itemHandle, itemText );
  571.         SelectDialogItemText( theDialog, iOtherSizeSizeEditText , 0, MAXSHORT );
  572.     }
  573.     else // else set it to the default from the prefs
  574.     {
  575.         NumToString( gMyPrefs.defSize, itemText );
  576.         itemHandle = HsoiGetDialogItemHandle( theDialog, iOtherSizeSizeEditText );
  577.         SetDialogItemText( itemHandle, itemText );
  578.         SelectDialogItemText( theDialog, iOtherSizeSizeEditText, 0, MAXSHORT );
  579.     }
  580.     
  581.     // show the window
  582.     
  583.     ShowWindow( GetDialogWindow(theDialog) );
  584.  
  585.     // here's where the MovableModalLib from Marco would call DisableMenuBar().  If you
  586.     // use this, make sure to comment out the following 2 lines (gInModalState and AdjustMenus)
  587.     // Having gInModalState = true and calling HsoiAdjustMenus() does the same sorta thing
  588.     
  589. //    DisableMenuBar( mEdit, -1 );
  590.         
  591.     gInModalState = true;
  592.     HsoiAdjustMenus();
  593.     
  594.     // now the fun stuff!  let's do the dialog.  note the funky use of a do-while loop
  595.     // and another do-while loop nested within it.  this is cause the first (nested one)
  596.     // actually does the dialog and the second is there to make sure only kosher
  597.     // values are entered into the dialog.  nifty?  you be the judge
  598.     
  599.     do{
  600.     
  601.         do {
  602.         
  603.             // first, we gotta make sure we have some kosher number in the dialog
  604.             
  605.             GetDialogItemText( itemHandle, itemText );
  606.                 
  607.             StringToNum( itemText, &fontSize );
  608.     
  609.             // here we used to call ModalDialog(), but now
  610.             // we'll just use Marco's Library to handle our movable modal dialog.
  611.             
  612.             MovableModalDialog( fontSizeFilterProc, &itemHit );
  613.             
  614.         } while ( (itemHit != ok) && (itemHit != cancel) );
  615.         
  616.         // ok...we've done the actual dialog stuff, now let's check for itemHits and
  617.         // also for kosher number entry
  618.         
  619.         // the user can do 3 things:  1. hit OK, 2. hit CANCEL 3. enter a number.
  620.         // don't matter much about canceling, but if they hit OK, we gotta make sure
  621.         // things are kosher...let's do so.
  622.         
  623.         if ( itemHit == ok )
  624.         {
  625.             itemHandle = HsoiGetDialogItemHandle( theDialog, iOtherSizeSizeEditText );
  626.             GetDialogItemText( itemHandle, itemText );
  627.             StringToNum( itemText, &fontSize );
  628.             zeroFont = false;
  629.         }
  630.         else  // this is just "arbitrary" to make sure things work right
  631.         {
  632.             fontSize = 12;    // so we don't get an "invalid size" sysbeep
  633.             zeroFont = true;
  634.         }    
  635.         
  636.         // if we got an invalid size, yell at the user and have em do it again.
  637.         
  638.         if ( (fontSize > kMaxFontSize) || (fontSize < kMinFontSize) )
  639.         {
  640.             HsoiDoIllegalFontSize();
  641.             SelectDialogItemText( theDialog, iOtherSizeSizeEditText, 0, MAXSHORT );
  642.         }
  643.     
  644.     } while ( (fontSize > kMaxFontSize) || (fontSize < kMinFontSize) );
  645.     
  646.     // all things are good, kosher font sizes, let's clean up
  647.     
  648.     DisposeRoutineDescriptor( fontSizeFilterProc );
  649.     
  650.     DisposeDialog( theDialog );
  651.     
  652.     gInModalState = false;
  653.     HsoiAdjustMenus();
  654.     
  655.     // and here we call ReEnableMenuBar() from Marco's MovableModalLib.  If you uncomment this,
  656.     // be sure to comment out the above 2 lines (gInModalState and HsoiAdjustMenus().
  657.     
  658. //    ReEnableMenuBar();
  659.     
  660.     if ( zeroFont )
  661.         fontSize = 0;
  662.         
  663.     return fontSize;
  664. }
  665.  
  666. /*
  667.  *    Here's the filter routine for the Other Font Size dialog.
  668.  */
  669.  
  670. // this also ought to check to see if the user attempts to paste something into the
  671. // dialog, cuase they might paste letters!
  672.  
  673. pascal Boolean hsoiOtherFontSizeDialogFilter( DialogRef theDialog, EventRecord *event, short *item )
  674. {
  675.     GrafPtr            oldPort;
  676.     char            theKey;
  677.     Boolean            retval = false;
  678.     Str255            textStr;
  679.     Boolean            okIsDimmed;
  680.     short            thePart;
  681.     WindowRef        window;
  682.     
  683.     // save the old graphics port and set the current one to our dialog.
  684.     
  685.     GetPort( &oldPort );
  686.     SetGrafPortOfDialog( theDialog );
  687.         
  688.     // see if there's any text in there.  if not, dim the ok button and snarf any return/enters
  689.     // oh, if the edit text box is initially empty (like when the dialog is brought up), the
  690.     // ok button should be but will not be dimmed (since this filter isn't called until after
  691.     // some event happens in the dialog).  But this is "worked around" by making sure that
  692.     // the dialog has something in the edit text when the dialog is brought up.
  693.     
  694.     GetDialogItemText( HsoiGetDialogItemHandle( theDialog, iOtherSizeSizeEditText ), textStr );
  695.     
  696.     // (remember, tho we're programming in C, strings on the Macintosh are stored/used
  697.     // in Pascal format.  So, no need to call strlen() or something, just look at the
  698.     // zero byte of the arry for the length...neat and simple
  699.     
  700.     if ( textStr[0] == 0 )
  701.     {
  702.         // no text in the field, we can't let them leave with nothing specified!  dim that OK
  703.         
  704.         HiliteControl( (ControlRef)HsoiGetDialogItemHandle( theDialog, ok ), kCtlInactive );
  705.         okIsDimmed = true;
  706.     }
  707.     else
  708.     {
  709.         // something's there...make sure it's not dimmed.
  710.         
  711.         HiliteControl( (ControlRef)HsoiGetDialogItemHandle( theDialog, ok ), kCtlActive );    
  712.         okIsDimmed = false;
  713.     }
  714.  
  715.     
  716.     // let's check for key related events.  
  717.     
  718.     if ( (event->what == keyDown) || (event->what == autoKey) )
  719.     {
  720.         theKey = event->message & charCodeMask;
  721.     
  722.         // to snarf or not to snarf, that is the question.  Well, in this case, if they
  723.         // hit the return/enter key and the OK button is dimmed, we ought to snarf that
  724.         // keypress
  725.             
  726.         if ( ((theKey == kEnterKey) || (theKey == kReturnKey)) && okIsDimmed )
  727.         {
  728.             retval = true;
  729.             goto exit;
  730.         }
  731.         else
  732.         {
  733.             retval = false;
  734.         }
  735.         
  736.         // and let's snarf some other things....if it's not one of a few certain keys,
  737.         // we'll complain.  The user only needs a few certain keys (numbers, return, etc)
  738.         // to deal with this dialog...and by restricting them somewhat, it can make our
  739.         // lives easier in ensuring that they don't enter any invalid stuff
  740.         
  741.         if ( !(theKey > 0x2F && theKey < 0x3A ) &&   // if it wasn't a number
  742.                 ( theKey != kEnterKey ) &&             // if it wasn't the Enter key
  743.                 ( theKey != kReturnKey ) &&             // if it wasn't the Return key
  744.                 ( theKey != kEscKey ) &&             // if it wasn't Escape
  745.                 ( theKey != kBackSpace ) &&             // if it wasn't backspace
  746.                 ( theKey != kDeleteKey ) &&             // if it wasn't the delete key
  747.                 ( theKey != kLeftArrow ) &&             // and all the arrow keys for easy editing
  748.                 ( theKey != kRightArrow ) &&
  749.                 ( theKey != kUpArrow ) &&
  750.                 ( theKey != kDownArrow ) )
  751.         {
  752.             SysBeep( 5 );
  753.             retval = true;    // we've handled it
  754.         }
  755.         else
  756.             retval = false; // let the Dialog Manager handle it
  757.     }
  758.     // check for mouse events!
  759.     else if ( event->what == mouseDown )
  760.     {
  761.         // check for mousedowns in the title bar (to allow dragging) and also for
  762.         // mousedowns in the menubar so people can still access system menus and the apple menu
  763.         // remember, this is a movable modal dialog box.
  764.         
  765.         thePart = FindWindow( event->where, &window );
  766.         
  767.         if ( thePart == inMenuBar )
  768.         {
  769.             MenuSelect( event->where );
  770.             retval = true;
  771.         }
  772.         
  773.         else if ( (window == GetDialogWindow(theDialog)) && (thePart == inDrag) )
  774.         {
  775.             HsoiDoDrag( event->where, GetDialogWindow(theDialog) );
  776.             retval = true;
  777.         }        
  778.     
  779.     }// end:  else if (mouseDown)
  780.  
  781.     // ok...that's about all the stuff we gotta handle, so if we didn't handle it in here,
  782.     // we should let the standard dialog filter routines kick in to handle it
  783.     
  784. exit:    
  785.     if ( !retval )
  786.         retval = hsoiMyStandardDialogFilter( theDialog, event, item );
  787.     
  788.     // clean up and go bye bye
  789.     
  790.     SetPort( oldPort );
  791.     
  792.     return retval;
  793. }
  794.  
  795. /*
  796.  *    This is just a little thing to complain to the user if they entered an
  797.  *    "illegal" font size somewhere
  798.  */
  799.  
  800. // it's pretty self explanitory as to what it does
  801.  
  802. void    HsoiDoIllegalFontSize( void )
  803. {
  804.     Str255        minSize, maxSize;
  805.  
  806.     // if we have a sound playing, stop it before we proceed.  any function that calls
  807.     // this should have already stopped the sound (if any), but just in case...
  808.     
  809.     if ( SoundIsPlaying() )
  810.         StopCurrentSound();
  811.     
  812.     NumToString( kMinFontSize, minSize );
  813.     NumToString( kMaxFontSize, maxSize );
  814.  
  815.     ParamText( minSize, maxSize, NIL_STRING, NIL_STRING );
  816.         
  817.     StopAlert( rIllegalFontSizeAlert, HsoiGetMyStandardDialogFilter() );
  818.     
  819.     return;
  820. }
  821.  
  822. #pragma mark -
  823. #pragma mark ••• Modal Dialog •••
  824.  
  825.  
  826. /******************************************************************************************\
  827.  *                                                                                          *
  828.  *                    BEGIN SECTION AND STUFF DEALING WITH MODAL DIALOGS                      *
  829.  *                                                         ^^^^^                              *
  830.  *                                                                                          *
  831.  *                                                                                          *
  832. \******************************************************************************************/
  833.  
  834.  
  835.  
  836. /*
  837.  *    The base code for this modal dialog comes from an Apple DTS Snippet called "DialogBits
  838.  *    2.0.1" by C.K. Haun.  I suppose he or Apple or whomever retains rights to the original. I just
  839.  *    thought to do this cause it explains a bunch of the neat-o things and FAQ's that
  840.  *    people want to do with dialogs.  It ain't perfect and probably has some bugs/shortcomings
  841.  *    but you get the point...I hope to fix those quirks sooner or later, but they're there.
  842.  *    Heck, it'd be a good exercise for you to fix them ;)  If you do, please send me the
  843.  *    code changes you made so I can keep releasing improvments to the Shell (you will get
  844.  *    credits of course :) ).
  845.  *
  846.  *    I've modified a lot of the code to get it to compile with CW (and Universal Headers)
  847.  *    and did some stuff to add in more functionality, customize, etc etc.  and of course,
  848.  *    to have PowerMac happiness.
  849.  *
  850.  *    If you're interested, I'm sure you can find the original code on
  851.  *    ftp.info.apple.com in the associated DTS/snippet's directories (can't give an exact
  852.  *    URL at this writing since Apple's ftp sites are in a state of flux as they are
  853.  *    constantly trying to perfect things)
  854.  */
  855.  
  856. void    HsoiDoModalDialog( void )
  857. {
  858.     DialogRef            myDialog = nil;
  859.     short                itemHit = 0;
  860.     Rect                iRect;
  861.     short                iItem;
  862.     Handle                iHandle;
  863.     Boolean                tempBool;
  864.     SndListHandle        theSound;
  865.     Str255                tempString;
  866.     ModalFilterUPP        myModalFilterProc = nil;
  867.     UserItemUPP            editLineDimmingProc = nil;
  868.     
  869.     // if we have a sound playing, stop it before we proceed
  870.     
  871.     if ( SoundIsPlaying() )
  872.         StopCurrentSound();
  873.     
  874.     // get the dialog from the resource fork
  875.     
  876.     myDialog = GetNewDialog( rModalDialog, nil, MOVE_TO_FRONT );
  877.  
  878.     if ( myDialog == nil )
  879.         return; // lame error handling, but eh...
  880.     
  881.     
  882.     // have the toolbox track the cursor movement.  no need to SetDialogDefault/CancelItem()
  883.     // cause the dialog filter handles that.
  884.  
  885.     SetDialogTracksCursor( myDialog, true );
  886.         
  887.     // set up the stuff to dim an edit line
  888.     
  889.     // get the UPP to the procedure
  890.     
  891.     editLineDimmingProc = NewUserItemProc( HsoiDimEditLine );
  892.     
  893.     // and install it for that item
  894.     
  895.     HsoiSetDialogItemProc( myDialog, iDimmingBox, editLineDimmingProc );
  896.         
  897.     // make sure the checkbox is unchecked
  898.     
  899.     iHandle = HsoiGetDialogItemHandle( myDialog, iEditCheckBox );
  900.     SetControlValue( (ControlRef)iHandle, false );
  901.     
  902.     // select the edit text.  this is good to do cause people can start typing.
  903.     // here there is no point, but you'll find it quite useful (to power users of
  904.     // your software especially) to make sure text is selected.
  905.     
  906.     SelectDialogItemText( myDialog, iTopEditLine, 0, MAXSHORT );
  907.     
  908.     // again, keep making sure that stuff is cosmetically set right
  909.     
  910.     HideDialogItem( myDialog, iEditTextVaryItem );
  911.     
  912.     // set up the radio buttons
  913.     
  914.     gCurrentRadio = 0;
  915.     HsoiSetRadioButton( myDialog, kRadioButtonFirst );
  916.     
  917.     // and now we're finally ready to show the window
  918.     
  919.     ShowWindow( GetDialogWindow(myDialog) );
  920.     
  921.     // grab the filter
  922.     
  923.     if ( myModalFilterProc == nil )
  924.         myModalFilterProc = NewModalFilterProc( hsoiFilterIt );
  925.     
  926.     // let's do it
  927.     
  928.     do
  929.     {
  930.         // hang out until something happens...
  931.         
  932.         ModalDialog( myModalFilterProc, &itemHit );
  933.         
  934.         // something happened...let's deal with it
  935.         
  936.         switch (itemHit)
  937.         {
  938.             // smacked Homer?  make him scream...
  939.             
  940.             case iIconItem:
  941.                 theSound = (SndListHandle)GetResource( TYPE_SOUND, rSoundIDHomer );
  942.                 if ( theSound != nil )
  943.                 {
  944.                     SndPlay( nil, theSound, false );
  945.                     HsoiForgetResource( (Handle *)&theSound );
  946.                 }
  947.                 else
  948.                     HsoiDoError( rErrorStrings, errCantLoadSound, 0, kErrGeneric );
  949.                 break;
  950.             
  951.             
  952.             // do they want to make the uneditable line editable (or vice versa)?
  953.             // if so, make it so.
  954.             
  955.             case iEditCheckBox:
  956.             
  957.                 // find out if the box is checked or not
  958.                 
  959.                 iHandle = HsoiGetDialogItemHandle( myDialog, iEditCheckBox );
  960.                 tempBool = GetControlValue( (ControlRef)iHandle );
  961.                 
  962.                 // depending on what it is, make it the other since we're switching
  963.                 
  964.                 if ( tempBool == true )
  965.                     tempBool = false;
  966.                 else
  967.                     tempBool = true;
  968.                 
  969.                 // set it as such
  970.                 
  971.                 SetControlValue( (ControlRef)iHandle, tempBool );
  972.                 
  973.                 // and if disabling the line, move the user to another edit field.
  974.                 
  975.                 if ( tempBool == false )
  976.                 {                    
  977.                     // FYI:  before Copland, in order to see which editField was
  978.                     // the active/current one, we had to do this:
  979.                     
  980.                     // if ( ( (DialogPeek)myDialog)->editField + 1 == iBottomEditLine )
  981.                     
  982.                     // but now with Copland (and accessor routines), we just call this
  983.                     // neat little function and viola!  the best part is, no more need
  984.                     // to do that "+ 1" stuff
  985.                     
  986.                     if ( GetDialogKeyboardFocusItem(myDialog) == iBottomEditLine )
  987.                         SelectDialogItemText( myDialog, iTopEditLine, 0, MAXSHORT );
  988.                 }
  989.                 
  990.                 // and whatever we do, make sure the edit line cosmetically looks right
  991.  
  992.                 GetDialogItem( myDialog, iDimmingBox, &iItem, &iHandle, &iRect );
  993.                 SetGrafPortOfDialog( myDialog );
  994.                 InvalRect( &iRect );
  995.                 break;
  996.             
  997.  
  998.             case iVaryTextCheckBoxItem:
  999.             
  1000.                 // grab a handle to the check box and get it's value
  1001.                 
  1002.                 iHandle = HsoiGetDialogItemHandle( myDialog, iVaryTextCheckBoxItem );
  1003.                 tempBool = GetControlValue( (ControlRef)iHandle );
  1004.                 
  1005.                 // manipulate the value a bit...
  1006.                 
  1007.                 tempBool = tempBool ? false : true;
  1008.                 
  1009.                 // and reset to a new value
  1010.                 
  1011.                 SetControlValue( (ControlRef)iHandle, tempBool );
  1012.                 
  1013.                 // now make things look right depending on the new value of
  1014.                 // the checkbox
  1015.                 
  1016.                 if ( tempBool )
  1017.                 {
  1018.                     HideDialogItem( myDialog, iStatTextVaryItem );
  1019.                     ShowDialogItem( myDialog, iEditTextVaryItem );
  1020.                 }
  1021.                 else
  1022.                 {
  1023.                     GetDialogItemText( HsoiGetDialogItemHandle( myDialog, iEditTextVaryItem), tempString );
  1024.                     SetDialogItemText( HsoiGetDialogItemHandle( myDialog, iStatTextVaryItem), tempString );
  1025.                     HideDialogItem( myDialog, iEditTextVaryItem );
  1026.                     ShowDialogItem( myDialog, iStatTextVaryItem );
  1027.                 }
  1028.             
  1029.                 if ( tempBool )
  1030.                 {
  1031.                     SelectDialogItemText( myDialog, iEditTextVaryItem, 0, MAXSHORT);
  1032.                 }
  1033.                 else
  1034.                 {
  1035.                     SelectDialogItemText( myDialog, iTopEditLine, 0, MAXSHORT );
  1036.                 }
  1037.                 
  1038.                 break;
  1039.         
  1040.         }    // end switch (itemHit )
  1041.         
  1042.         //    Put the radio button check here to allow for ease in expanding the number
  1043.         //    of radio buttons ("if" is much easier to use than "switch"), plus,
  1044.         //    for ease of implimentation if you have more than 1 group of radio buttons
  1045.         //    in a dialog
  1046.         
  1047.         if ((itemHit >= kRadioButtonFirst) && (itemHit <= kRadioButtonLast ) )
  1048.             HsoiSetRadioButton( myDialog, itemHit );
  1049.         
  1050.     } while ( itemHit != ok && itemHit != cancel );
  1051.     
  1052.     // clean up
  1053.     
  1054.     DisposeRoutineDescriptor( myModalFilterProc );
  1055.     DisposeRoutineDescriptor( editLineDimmingProc );
  1056.     
  1057.     DisposeDialog( myDialog );
  1058.     InitCursor();
  1059.     HsoiAdjustMenus();
  1060.     
  1061.     return;
  1062. }
  1063.  
  1064. /*
  1065.  *  This is the monster dialog filter routine for our big modal dialog
  1066.  */
  1067.  
  1068. pascal Boolean hsoiFilterIt( DialogRef inputDialog, EventRecord *myDialogEvent, short *theDialogItem )
  1069. {
  1070.     WindowRef             tempWindow;
  1071.     char                 theKey;
  1072.     Rect                 tempRect;
  1073.     short                 tempItem;
  1074.     Handle                 tempHandle;
  1075.     Boolean             returnVal = false;
  1076.     char                 tempKey;
  1077.     Str255                 myStr;
  1078.     long                 offset;
  1079.     short                 selection;
  1080.     long                 scrapLen;
  1081.     short                 resultLen;
  1082.     Point                 mousePoint;
  1083.     Boolean             hiLit = false;
  1084.     Point                 tempPoint;
  1085.     short                 thePart;
  1086.     ControlRef            returnedControl;
  1087.     Boolean             wasAKey = false;    
  1088.     ControlActionUPP    theScrollProc;
  1089.     
  1090.     
  1091.     // save the current port, and set the port to us
  1092.  
  1093.     GetPort(&(GrafPtr)tempWindow);
  1094.     SetGrafPortOfDialog(inputDialog);
  1095.     
  1096.     // Use something like this if you want to do any idle time drawing in your
  1097.     // dialog, like a clock, flashing cursor, or a classy animated icon like I'm using
  1098.  
  1099.     HsoiSpinIt(inputDialog);
  1100.     
  1101.  
  1102.     // Some key filtering schemes follow.  The first is the standard filter to
  1103.     // recognize 'return' as OK and 'ESC' as cancel.  What this really means
  1104.     // is that I never ever want to have to use the mouse to click the cancel
  1105.     // buttton ever again, you can just cut and paste this code from now on.
  1106.  
  1107.     // do standard filtering for escape and return as OK and Cancel aliases
  1108.     // We also invert the button in the dialog, so the user get's visual feedback
  1109.     // about the action they just took
  1110.  
  1111.     // see if the event was a key being pressed down
  1112.     
  1113.     wasAKey = (myDialogEvent->what == keyDown) || (myDialogEvent->what == autoKey);
  1114.  
  1115.         // this 'if' has a double key check because of the 'tab' key restriction
  1116.         // I'm doing. we do NOT want to pass the tab key through to the standard 
  1117.         // filter, since it will tab to the other edit line even if we have it turned off
  1118.  
  1119.  
  1120.     if ( (wasAKey && ((myDialogEvent->message & charCodeMask) == kTabKey)) && wasAKey )
  1121.     {
  1122.         theKey = myDialogEvent->message & charCodeMask;
  1123.         switch (theKey)
  1124.         {
  1125.             // some of this stuff we don't need to worry about since we're using those
  1126.             // wonderful new System 7 Dialog Manager routines...it's redundant to "click"
  1127.             // the OK button when SetDialogDefaultItem() will do it for us :)
  1128.             // but let's at least make sure theDialogItem is set to the right dialog item
  1129.             
  1130.             case kReturnKey:
  1131.             case kEnterKey:                                 // enter key
  1132.                 // This filters for Return or Enter as item 1, and Esc as item 2
  1133.                 *theDialogItem = ok;                        // change whatever the current item is to the OK item
  1134.             break;
  1135.  
  1136.                 // This filters the escape key as the same as item 2 (the canx button, usually )
  1137.             case kEscKey:
  1138.                 *theDialogItem = cancel;
  1139.             break;
  1140.  
  1141.             case kTabKey:
  1142.                 // I'm filtering the tab key here so the user cannot tab to
  1143.                 // my inactive edit line
  1144.                 if (GetControlValue(HsoiSnatchHandle(inputDialog, iEditCheckBox)) == false)
  1145.                 {                
  1146.                     returnVal = true;                       // don't allow edit line swaps
  1147.                 }
  1148.             break;
  1149.         }
  1150.     }
  1151.     
  1152.     // Here's another kind of key filtering you need every so often, text or numeric
  1153.     // filtering.  In this case, we're only going to allow non-numeric characters in
  1154.     // the second edit line we have installed in this dialog
  1155.     // Any number (1,2,3,4,5,6,7,8,9,0) will be eaten, and a beep generated
  1156.  
  1157.     /*    In the original code by C.K. Haun, the number filter was only filtering out 1-8
  1158.         inclusive.  9 and 0 still got through.  The "if" statement below:
  1159.         
  1160.         if ((theKey...etc
  1161.         
  1162.         used to be > 0x30 && < 0x39.
  1163.         
  1164.         I think this is the problem...i don't know keyCodes and charCodes that well, and
  1165.         the charCodeMask just makes my life better (bitvectors and manipulations on bit
  1166.         vectors (& | ^ ~) are a weak point in my programming knowledge.
  1167.         
  1168.         But, if i fanagled it right, the way it is now, > 0x2F && < 0x3A should work
  1169.         to filter out 1,2,3,4,5,6,7,8,9,0.
  1170.         
  1171.         If you find it doesn't, please notify me.  John Daub.
  1172.     */
  1173.     
  1174.     if (wasAKey)
  1175.     {
  1176.         theKey = myDialogEvent->message & charCodeMask;
  1177.  
  1178.         if ((theKey > 0x2F && theKey < 0x3A) &&
  1179.                 GetDialogKeyboardFocusItem(inputDialog) == iBottomEditLine)
  1180.               
  1181.         {
  1182.             // Dang, it's a number and in the wrong edit line, reject it
  1183.             SysBeep(1);                                     // complain a little
  1184.             returnVal = true;                               // tell the dialog manager
  1185.                                                             // that we handled this already and
  1186.             // it doesn't have to, so the keystroke will _not_ get
  1187.             // added to the edit line
  1188.             
  1189.         }
  1190.     }
  1191.     
  1192.     // Here's yet another kind of key filtering you need every so often.
  1193.     // I'm going to restrict the amount of text in the top edit line to just 25 characters
  1194.  
  1195.     // •• NOTE: Remember Cut/Copy/Paste!
  1196.     // Before you allow these, you need to see what the result of a Paste (in this case)
  1197.     // will be, since a Paste can also drive you over the 25 char limit.
  1198.     // I've modified the function IsEditKey to look for these
  1199.     // I've also added code that checks to see if there is a selection range,
  1200.     // since typeing one charater to replace 5 is OK
  1201.     
  1202.     // First, see if it was a key and the top edit line is active
  1203.  
  1204.     if ( wasAKey && (GetDialogKeyboardFocusItem(inputDialog) == iTopEditLine) )
  1205.     {
  1206.         selection = HsoiHasSelectionRange((DialogPeek)inputDialog);
  1207.         scrapLen = GetScrap(nil, TYPE_TEXT, &offset);
  1208.         GetDialogItem(inputDialog, iTopEditLine, &tempItem, &tempHandle, &tempRect);
  1209.         GetDialogItemText(tempHandle, myStr);
  1210.  
  1211.         // calculate the result of adding the scrap to the current record.  We use
  1212.         // this in a few places here
  1213.  
  1214.         resultLen = myStr[0] + (scrapLen - selection);
  1215.         theKey = myDialogEvent->message & charCodeMask;
  1216.         tempKey = theKey;
  1217.         if (tempKey >= 0x61 && tempKey <= 0x7a)
  1218.             tempKey -= 0x20;
  1219.         if (myStr[0] > 25)                            // over 25, see what it is
  1220.         {
  1221.             if (HsoiIsEditKey(theKey, myDialogEvent->modifiers))
  1222.             {
  1223.                 // it was an editing key, but it MAY be a command-V.
  1224.                 // If it's a command-V then we won't allow it UNLESS
  1225.                 // there is a slection range AND the new data won't overrun things
  1226.             
  1227.                 if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey))
  1228.                 {
  1229.                     
  1230.                     // this was a paste.  check selection range and scrap len 
  1231.                 
  1232.                     if (resultLen < 26)
  1233.                     {
  1234.                         returnVal = false;                  // net result is  25 or less
  1235.                     } 
  1236.                     else
  1237.                     {
  1238.                         SysBeep(1);
  1239.                         returnVal = true;
  1240.                     }
  1241.                 }
  1242.                 else
  1243.                 {
  1244.                     returnVal = false;                      // don't filter out editing keys
  1245.                 }
  1246.             }
  1247.             else
  1248.             {
  1249.                 // One more check (this can get complicated, huh?)
  1250.                 // We now look to see if there is a selection range.  If there
  1251.                 // is a range of 1 or more characters, then the one character they are entering
  1252.                 // now will replace that, and we'll end up with _less_ than 25 (or equal)
  1253.                 // to do this, we have to get the TERecord out of the dialog. 
  1254.                 // I'm going to do this in a seperate function
  1255.                 if (selection == 0)
  1256.                 {
  1257.                     SysBeep(1);                             // complain a little
  1258.                     returnVal = true;                       // tell the dialog manager that we handled this already and
  1259.                     // it doesn't have to, so the keystroke will _not_ get
  1260.                     // added to the edit line
  1261.                 }
  1262.             }
  1263.         }
  1264.         else
  1265.         {
  1266.             // even if we're less than 25 currently, a Command-V (paste) could put us over
  1267.             // so check it out
  1268.             
  1269.             if ((tempKey == 'V') && (myDialogEvent->modifiers & cmdKey)) {
  1270.                 
  1271.                 // Gettting the scrap with a nil handle, which does not give us data, just
  1272.                 // returns the size
  1273.                 if (resultLen > 25)
  1274.                 {
  1275.                     SysBeep(1);                             // complain a little
  1276.                     returnVal = true;                       // tell the dialog manager that we handled this already and
  1277.                     
  1278.                 }
  1279.             }
  1280.         }
  1281.     }
  1282.     
  1283.     // We are doing three checks here in the dialog filter for  mouseDown
  1284.     // events.
  1285.     // The first checks to see if we're in the icon and tracks it like a control if we are.
  1286.     // If we're not, then we may be in our scroll bar, and we have to
  1287.     // do various things if that is true.
  1288.     // Or, we may be in the disabled edit line, and we have to disallow clicks on it
  1289.     // when it's disabled
  1290.     
  1291.     if (myDialogEvent->what == mouseDown)
  1292.     {
  1293.         mousePoint = (myDialogEvent->where);
  1294.         GlobalToLocal(&mousePoint);
  1295.         
  1296.         // First see if we're in the icon
  1297.         
  1298.         GetDialogItem(inputDialog, iIconItem, &tempItem, &tempHandle, &tempRect);
  1299.         if (PtInRect(mousePoint, &tempRect)) {
  1300.         
  1301.             // invert my icon, and track it whilst the user holds the mouse down
  1302.         
  1303.             InvertRect(&tempRect);
  1304.             hiLit = true;
  1305.             while (StillDown())
  1306.             {
  1307.                 GetMouse(&tempPoint);                       // returns point in local coords
  1308.                 if (PtInRect(tempPoint, &tempRect))
  1309.                 {
  1310.                     // in the rect.  See if it's hilighted or not
  1311.                 
  1312.                     if (hiLit == false)
  1313.                     {
  1314.                         hiLit = true;
  1315.                         InvertRect(&tempRect);
  1316.                     }
  1317.                 }
  1318.                 else
  1319.                 {
  1320.                     // not in the rectangle.  If it's hilit, get rid of that
  1321.                 
  1322.                     if (hiLit == true)
  1323.                     {
  1324.                         hiLit = false;
  1325.                         InvertRect(&tempRect);
  1326.                     }
  1327.                 }
  1328.             }
  1329.             if (hiLit == true)
  1330.             {
  1331.                 // if it's still hilited when the mouse comes up, then that means the
  1332.                 // user stayed in and wants to take this icon action
  1333.             
  1334.                 InvertRect(&tempRect);                      // clear the hiliting if it's still lit
  1335.                 *theDialogItem = iIconItem;
  1336.                 returnVal = true;                           // telling the Dialog Manager we handled it, pass item back
  1337.             }
  1338.         }
  1339.         else
  1340.         {
  1341.             // Now see if we're in the scroll bar
  1342.             
  1343.             GetDialogItem(inputDialog, iScrollControlItem, &tempItem, &tempHandle, &tempRect);
  1344.             if (PtInRect(mousePoint, &tempRect))
  1345.             {
  1346.                 // We're in the scroll bar.
  1347.                 // Now, what does that mean????
  1348.                 // Well, the Dialog Manager will automatically call FindControl and TrackControl
  1349.                 // and set the control value (in the case of scroll thumbs)
  1350.                 // on controls added to your dialog, and in many cases that's all you're going
  1351.                 // to need.
  1352.                 // But, ModalDialog does NOT pass back a part code, so if the userPerson
  1353.                 // clicked on the thumb or arrows of the scroll bar, you won't know, you'll
  1354.                 // just know that the  scroll bar was clicked in
  1355.                 // That's not enough, so we'll to an initial check to see where the control
  1356.                 // was hit
  1357.              
  1358.                 thePart = FindControl(mousePoint, inputDialog, &returnedControl);
  1359.              
  1360.                 // if the hit was in an arrow or page area, we'll handle it ourselfs
  1361.              
  1362.                 if (thePart != kControlIndicatorPart)
  1363.                 {
  1364.                     theScrollProc = NewControlActionProc( HsoiDoScrollArrows );
  1365.                     TrackControl(returnedControl, mousePoint, theScrollProc );
  1366.                     DisposeRoutineDescriptor( theScrollProc );
  1367.                     returnVal = true;
  1368.                 }
  1369.  
  1370.                 // if it was in the thumb, we'll just fall through and let the Dialog Manager
  1371.                 // handle it for us
  1372.  
  1373.             }
  1374.             else
  1375.             {
  1376.                 // first see if we even care about this click.  If the check box is true, then
  1377.                 // both edit lines are active, let the dialog manager handle it
  1378.             
  1379.                 if (GetControlValue(HsoiSnatchHandle(inputDialog, iEditCheckBox)))
  1380.                 {
  1381.                     returnVal = false;                      // DM will handle
  1382.                 }
  1383.                 else
  1384.                 {
  1385.                     // OK, so the edit line checkbox is NOT set, which means that we don't want
  1386.                     // hits in the inactive edit line to do anything.  So, see if the hit was
  1387.                     // in the edit line, and report 'true' if it was, telling the Dialog Manager that
  1388.                     // you handled the event and it should do nothing
  1389.                 
  1390.                     GetDialogItem(inputDialog, iBottomEditLine, &tempItem, &tempHandle, &tempRect);
  1391.                     if (PtInRect(mousePoint, &tempRect))
  1392.                     {
  1393.                         returnVal = true;
  1394.                     }
  1395.                     else
  1396.                     {
  1397.                         returnVal = false;
  1398.                     }
  1399.                 }
  1400.             }
  1401.         }
  1402.     }
  1403.     // one final thing if we're under System 7,
  1404.     // calling the standard filter.
  1405.     // You MUST call the standard filter if you want any of the
  1406.     // new things to happen!
  1407.     // The OK button border, cursor tracking, and the rest ONLY
  1408.     // happen if you call the filter!
  1409.     // I am also only doing this if the returnValue is still false.  If I have
  1410.     // set it to true somewhere in here, I don't want to call the stdFilter
  1411.  
  1412.     // Let's call our own hsoiMyStandardDialogFilter to make sure stuff in the
  1413.     // background gets updated correctly (it calls the standard dialog filter anyways)
  1414.     
  1415.     // furthermore, the above calls to the standard modal filter proc can be commented
  1416.     // out cause our filter calls it anyways...why do it twice?
  1417.  
  1418.     if ( !returnVal )
  1419.         returnVal = hsoiMyStandardDialogFilter( inputDialog, myDialogEvent, theDialogItem );
  1420.     
  1421.     return(returnVal);
  1422. } // end filterIt
  1423.  
  1424.  
  1425.  
  1426.  
  1427. // SpinIt animates my fancy icon
  1428. void    HsoiSpinIt(DialogRef theDialog)
  1429. {
  1430.     static short pos;
  1431.     static long count;
  1432.     Handle myIcon;
  1433.     Rect tempRect;
  1434.     short tempItem;
  1435.     Handle tempHandle;
  1436.  
  1437.     // I'm adjusting the speed of the spin based on the value of the scroll bar
  1438.  
  1439.     if (TickCount() > count + (10 - GetControlValue(HsoiSnatchHandle(theDialog, iScrollControlItem))))
  1440.     {
  1441.         count = TickCount();                                // reset count to next value
  1442.         myIcon = GetIcon(pos + rBaseSpinIcon);
  1443.     
  1444.         // you could have a rect in this function, but that'd require you to change it all 
  1445.         // the time when you move the item around in your dialog.  So, we'll reference it 
  1446.         // from the dialog record instead
  1447.         // make sure we really got the handle
  1448.     
  1449.         if (myIcon != nil)
  1450.         {
  1451.             GetDialogItem(theDialog, iSpinItem, &tempItem, &tempHandle, &tempRect);
  1452.             PlotIcon(&tempRect, myIcon);
  1453.             HsoiForgetResource( &myIcon );
  1454.         }
  1455.         pos++;
  1456.         if (pos > 3)
  1457.             pos = 0;
  1458.     }
  1459. } // end SpinIt
  1460.  
  1461. // This userItem dims the bottom edit line if the check box is not checked
  1462.  
  1463. pascal void HsoiDimEditLine(WindowRef dwind, short dinum)
  1464. {
  1465.     ControlRef tempCont = HsoiSnatchHandle(dwind, iEditCheckBox);
  1466.  
  1467.     // only do it if the checkbox is false
  1468.  
  1469.     if (GetControlValue(tempCont) == false)
  1470.     {
  1471.         PenState thePen;
  1472.         Rect dimRect;
  1473.     
  1474.         // Save and restore the pen state so we don't mess things up for other
  1475.         // drawing routines
  1476.     
  1477.         GetPenState(&thePen);
  1478.         HsoiGetDialogItemRect( dwind, dinum, &dimRect );
  1479.         PenMode(notPatBic);
  1480.         PenPat(&qd.gray);
  1481.         PaintRect(&dimRect);
  1482.         SetPenState(&thePen);
  1483.         
  1484.     }
  1485.     
  1486.     return;
  1487. } // end DimEditLine
  1488.  
  1489.  
  1490. // This little routine adjusts the scroll bar during TrackControl
  1491.  
  1492. pascal void HsoiDoScrollArrows(ControlRef theControl, short thePart)
  1493. {
  1494.     short currentVal = GetControlValue(theControl);
  1495.     short offSet = 0;
  1496.  
  1497.     switch (thePart)
  1498.     {
  1499.         case kControlUpButtonPart:
  1500.             offSet = -1;
  1501.             break;
  1502.     
  1503.         case kControlDownButtonPart:
  1504.             offSet = 1;
  1505.             break;
  1506.     
  1507.         case kControlPageUpPart:
  1508.             offSet = -3;
  1509.             break;
  1510.     
  1511.         case kControlPageDownPart:
  1512.             offSet = 3;
  1513.             break;
  1514.             
  1515.     }
  1516.     
  1517.     // set the control value to the new one, as long as it doesn't pass limits
  1518.     
  1519.     currentVal += offSet;
  1520.     if (currentVal < 1)
  1521.         currentVal = 1;
  1522.     if (currentVal > 10)
  1523.         currentVal = 10;
  1524.     SetControlValue(theControl, currentVal);
  1525.     
  1526.     return;
  1527.     
  1528. } // end DoScrollArrows
  1529.  
  1530.  
  1531.  
  1532.  
  1533. /******************************************************************************************\
  1534.  *                                                                                          *
  1535.  *                    END SECTION AND STUFF DEALING WITH MODAL DIALOGS                      *
  1536.  *                                                       ^^^^^                              *
  1537.  *                                                                                          *
  1538.  *                                                                                          *
  1539. \******************************************************************************************/
  1540.  
  1541.  
  1542. #pragma mark -
  1543. #pragma mark ••• Modeless Dialog •••
  1544.  
  1545.  
  1546. /******************************************************************************************\
  1547.  *                                                                                          *
  1548.  *                    BEGIN SECTION AND STUFF DEALING WITH MODELESS DIALOGS                  *
  1549.  *                                                         ^^^^^^^^                          *
  1550.  *                                                                                          *
  1551.  *                                                                                          *
  1552. \******************************************************************************************/
  1553.  
  1554.  
  1555.  
  1556.  
  1557. /*
  1558.  *    Since I don't really have a need right now to use modeless dialogs, this code
  1559.  *    for all the modeless dialogs is taken straight from Knaster's MPS book (with
  1560.  *    modifications to work with HAS and Copland)
  1561.  */
  1562.  
  1563. void    HsoiDoModelessDialog( void )
  1564. {
  1565.     // if we have a sound playing, stop it before we proceed.  this might be one place
  1566.     // were we don't wnat to stop a playing sound, since this is a modeless dialog.
  1567.     // but for now, we'll stop it.
  1568.     
  1569.     if ( SoundIsPlaying() )
  1570.         StopCurrentSound();
  1571.  
  1572.     // if we don't have the dialog already, get it.
  1573.     
  1574.     if ( gModelessDialog == nil )
  1575.     {
  1576.         gModelessDialog = GetNewDialog( rModelessDialog, nil, MOVE_TO_FRONT );
  1577.     }
  1578.     
  1579.     // set the dialog's windowKind for menu adjustment
  1580.     
  1581. //    SetWindowKind( GetDialogWindow( gModelessDialog ), kFindDialogKind );
  1582.     
  1583.     // show it
  1584.     
  1585.     ShowWindow( GetDialogWindow(gModelessDialog) );
  1586.     SelectWindow( GetDialogWindow(gModelessDialog) );
  1587.     SetGrafPortOfDialog( gModelessDialog );
  1588.     
  1589.     // adjust the menus to suit
  1590.     
  1591.     HsoiAdjustMenus();
  1592.     
  1593.     return;
  1594. }
  1595.  
  1596.  
  1597.  
  1598.  
  1599. /******************************************************************************************\
  1600.  *                                                                                          *
  1601.  *                    END SECTION AND STUFF DEALING WITH MODELESS DIALOGS                         *
  1602.  *                                                       ^^^^^^^^                              *
  1603.  *                                                                                          *
  1604.  *                                                                                          *
  1605. \******************************************************************************************/
  1606.  
  1607.  
  1608. //    The following function is used by both the modeless and movable modal dialogs
  1609. //    to determine if a dialog item was hit (the ok button, so dismiss the dialog)
  1610.         
  1611. void    HsoiDoDialogHit( DialogRef dlg, short item )
  1612. {
  1613.     if ( item == ok )    // cause that's all they can hit...if you add more buttons to your dialog, you'll need to handle them appropriately
  1614.     {
  1615.         // just hide the window...don't dispose of it.  this way, if the user brings it
  1616.         // up again, it'll be in the same place they last left it, stuff in the dialog
  1617.         // will be set like they left it, etc.
  1618.         
  1619.         HideWindow( GetDialogWindow(dlg) );
  1620.         
  1621.         // and if the dialog is the movable modal progress bar, make sure to reset
  1622.         // some of the globals and get things back to normal
  1623.         if ( dlg == gMovableModalDialog )
  1624.         {
  1625.             gInModalState = false;
  1626.             gPeriodicTask = false;
  1627.             SetCursor( &qd.arrow );
  1628.             HsoiAdjustMenus();
  1629.         }
  1630.     }
  1631.     
  1632.     return;
  1633.     
  1634. }    
  1635.  
  1636.  
  1637. #pragma mark -
  1638. #pragma mark ••• Movable Modal Dialog •••
  1639.  
  1640. /******************************************************************************************\
  1641.  *                                                                                          *
  1642.  *                BEGIN SECTION AND STUFF DEALING WITH MOVABLE MODAL DIALOGS                     *
  1643.  *                                                     ^^^^^^^^^^^^^                             *
  1644.  *                                                                                          *
  1645.  *                                                                                          *
  1646. \******************************************************************************************/
  1647.  
  1648.  
  1649.  
  1650. /*
  1651.  *  This implimentation of the movable modal dialog will do a progress bar as per
  1652.  *    Knaster's MPS code.
  1653.  *    
  1654.  */
  1655.  
  1656. /*    A note on successful doing of this code...
  1657.  
  1658.     I ran into problems with getting the progress bar to draw in color...it would only
  1659.     draw in black and white even tho all my code was working properly to draw color.
  1660.     
  1661.     Problem?  It was my resources...
  1662.     
  1663.     The 'DLOG' resource for the movable modal (for the progress bar dialog is actually
  1664.     more appropriate) was a pure b/w resource...no color resources were attached to
  1665.     that 'DLOG' resource.  I needed to have a 'dtcb' resource for that 'DLOG' resource
  1666.     (same numbers, 202 in this case) to make that dialog box a color dialog.
  1667.     
  1668.     THEN (and only then) will color happily show up in the dialog...
  1669.     
  1670.     So remember this if you run into similar situations...
  1671.     
  1672.     Thanx go to muffinhead@ins.infonet.net (MuffinHead) from Armpit Studios VII in
  1673.     Iowa City, Iowa for the help and fix :) (i owe him $2 for it) ;)
  1674. */
  1675.  
  1676. void    HsoiDoMovableModalDialog( void )
  1677. {
  1678.     Handle        iHandle;
  1679.     Rect        iRect;
  1680.     Str255        theString;
  1681.  
  1682.     // if we have a sound playing, stop it before we proceed
  1683.     
  1684.     if ( SoundIsPlaying() )
  1685.         StopCurrentSound();
  1686.     
  1687.     // if we don't have the dialog yet, get it
  1688.     
  1689.     if ( gMovableModalDialog == nil )
  1690.     {
  1691.         gMovableModalDialog = GetNewDialog( rMovableModalProgressDialog, nil, MOVE_TO_FRONT );
  1692.         
  1693.         // set the text in the dialog to tell the user what's going on.
  1694.         
  1695.         GetIndString( theString, rMovableModalStrings, strDoingLongTask );
  1696.         iHandle = HsoiGetDialogItemHandle( gMovableModalDialog, iMMProgressStaticText );
  1697.         SetDialogItemText( iHandle, theString );
  1698.     }
  1699.     
  1700.     // show the dialog
  1701.     
  1702.     ShowWindow( GetDialogWindow(gMovableModalDialog) );
  1703.     SelectWindow( GetDialogWindow(gMovableModalDialog) );
  1704.     SetGrafPortOfDialog( gMovableModalDialog );
  1705.     
  1706.     // get ready to make the progress bar update (initialize it)
  1707.     
  1708.     HsoiGetDialogItemRect( gMovableModalDialog, iMMProgressBar, &iRect );
  1709.     HsoiInitProgressIndicator( gMovableModalDialog, iRect, 500 );
  1710.     
  1711.     // set our globals
  1712.     
  1713.     gPeriodicTask = true;
  1714.     gInModalState = true;
  1715.  
  1716.     // start the cursor spinning
  1717.     
  1718.     HsoiStartManualSpinning();    
  1719.     
  1720.     // adjust the menus
  1721.     
  1722.     HsoiAdjustMenus();
  1723.     
  1724.     return;
  1725.  
  1726. }
  1727.  
  1728. // this function sets the progress bar values to their initial values
  1729.  
  1730. void HsoiInitProgressIndicator(GrafPtr ourPort, Rect r, long max)
  1731. {
  1732.     pProgressPort = ourPort;
  1733.     pRect = r;
  1734.     pMax = max;
  1735.     pCurrent = 0;
  1736.     pLastCurrent = 0;
  1737.     pLastBorder = 0;
  1738. }
  1739.  
  1740.  
  1741. void HsoiSetProgress(long absoluteAmount)
  1742. {
  1743.     pCurrent = absoluteAmount;
  1744.     HsoiDrawProgressBar();
  1745. }
  1746.  
  1747.  
  1748. Boolean HsoiSetProgressDelta(long delta)
  1749. {
  1750.     pCurrent += delta;
  1751.     HsoiDrawProgressBar();
  1752.     return (pCurrent >= pMax);
  1753. }
  1754.  
  1755.  
  1756. void HsoiDrawProgressBar( void )
  1757. {
  1758.     short        border;
  1759.     short        rectWidth;
  1760.  
  1761.     if ((pLastCurrent != pCurrent) && (pCurrent <= pMax)) {
  1762.         pLastCurrent = pCurrent;
  1763.         rectWidth = pRect.right - pRect.left - 2;
  1764.         border = pRect.left + 1 + rectWidth * pCurrent / pMax;
  1765.         if (pLastBorder != border) {
  1766.             pLastBorder = border;
  1767.             HsoiUpdateProgressBar();
  1768.         }
  1769.     }
  1770. }
  1771.  
  1772.  
  1773. void HsoiUpdateProgressBar( void )
  1774. {
  1775.     GrafPtr        oldPort;
  1776.     RGBColor    oldForeColor;
  1777.     RGBColor    oldBackColor;
  1778.  
  1779.     Rect        doneRect;
  1780.     Rect        toDoRect;
  1781.  
  1782.     doneRect = pRect;
  1783.     InsetRect(&doneRect, 1, 1);
  1784.     toDoRect = doneRect;
  1785.  
  1786.     doneRect.right = toDoRect.left = pLastBorder;
  1787.  
  1788.     GetPort(&oldPort);
  1789.     SetPort(pProgressPort);
  1790.     GetForeColor(&oldForeColor);
  1791.     GetBackColor(&oldBackColor);
  1792.     PenNormal();
  1793.  
  1794.     HsoiSetFrameColor();
  1795.     FrameRect(&pRect);
  1796.  
  1797.     HsoiSetDoneColor();
  1798.     PaintRect(&doneRect);
  1799.  
  1800.     HsoiSetToDoColor();
  1801.     PaintRect(&toDoRect);
  1802.  
  1803.     RGBForeColor(&oldForeColor);
  1804.     RGBBackColor(&oldBackColor);
  1805.     SetPort(oldPort);
  1806. }
  1807.  
  1808.  
  1809.  
  1810. void HsoiSetFrameColor( void )
  1811. {
  1812.     if (gHasColorQD) {
  1813.         RGBForeColor(&kMMBlack);
  1814.         RGBBackColor(&kMMWhite);
  1815.     } else {
  1816.         PenPat(&qd.black);
  1817.     }
  1818. }
  1819.  
  1820. void HsoiSetDoneColor( void )
  1821. {
  1822.     if (gHasColorQD) {
  1823.         RGBForeColor(&kMMDarkGrey);
  1824.         RGBBackColor(&kMMWhite);
  1825.     } else {
  1826.         PenPat(&qd.black);
  1827.     }
  1828. }
  1829.  
  1830. void HsoiSetToDoColor( void )
  1831. {
  1832.     if (gHasColorQD) {
  1833.         RGBForeColor(&kMMSteelBlue);
  1834.         RGBBackColor(&kMMBlack);
  1835.     } else {
  1836.         PenPat(&qd.white);
  1837.     }
  1838. }
  1839.  
  1840.  
  1841. /******************************************************************************************\
  1842.  *                                                                                          *
  1843.  *                END SECTION AND STUFF DEALING WITH MOVABLE MODAL DIALOGS                     *
  1844.  *                                                   ^^^^^^^^^^^^^                             *
  1845.  *                                                                                          *
  1846.  *                                                                                          *
  1847. \******************************************************************************************/
  1848.  
  1849.  
  1850.